<?php
	/**
	  * @package	MyTools
	  * @name		MEMStats
	  * @brief		Clase para obtener el estado de la memoria
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://opensource.org/licenses/gpl-2.0.php
	  * @date		2010-01-27
	  * @version	0.1.1
  	**/

	final class MEMStats extends MyDebuger implements MyVersions {
		/* version de la clase */
		private static $version			= 0;
		/* subversion de la clase */
		private static $subversion		= 1;
		/* numero de revision de la clase */
		private static $revision		= 1;

		/* Estados de las memorias RAM y SWAP */
		private $results	= Array();
		/* Comando de ejecucion */
		private $command	= 'free -ob';

		public function __construct($debug = False) {
			/* creamos el padre */
			parent::__construct($debug, __CLASS__);
		}

		public function __destruct() {
			/* matamos el padre */
			parent::__destruct();
		}

		public static final function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		public function getData($type = 'ram') {
			/* obtenemos los datos */
			$this->catchExceptions('getDataInternal', $type);
			/* retornamos el valor solicitado */
			return (
				/* verificamos si existe */
				isset($this->results[$type]) ?
				/* retornamos el valor */
				$this->results[$type] :
				/* retornamos false */
				False
			);
		}

		private function getDataInternal($type) {
			/* cargamos el estado actual de la memoria */
			$this->checkLoad();
			/* verificamos que el valor solicitado existe */
			$this->verificarSolicitud($type);
		}

		private function verificarSolicitud($type) {
			/* mostramos un mensaje */
			$this->show('Verificando solicitud..', False);
			/* verificamos si existe la clave */
			if (!array_key_exists($type, $this->results))
				/* si no existe finalizamos con un error */
				$this->newException('Opcion incorrecta');
			/* mostramos OK al mensaje */
			$this->showOK();
		}

		private function checkLoad() {
			/* mostramos un mensaje */
			$this->show('Obteniendo datos..');
			/* obtenemos los datos actuales de la memoria */
			$this->getMemData();
			/* mostramos un mensaje */
			$this->show('Procesando datos..');
			/* procesamos los datos */
			$this->processData();
		}

		private function getMemData() {
			/* vaciamos los datos actuales */
			$this->emptyData();
			/* ejecutamos el comando para obtener los datos */
			$this->ejecutarComando();
			/* limpiamos los resultados */
			$this->cleanResults();
		}

		private function emptyData() {
			/* vaciamos los datos actuales (si existieren) */
			$this->results = Array();
		}

		private function ejecutarComando() {
			/* mostramos un mensaje */
			$this->show('Ejecutando comando..', False);
			/* ejecutamos el comando para obtener los datos */
			exec($this->command, $this->results);
			/* ok al mensaje */
			$this->showOK();
		}

		private function cleanResults() {
			/* mostramos un mensaje */
			$this->show('Limpiando resultados..', False);
			/* eliminamos los titulos que no son necesarios */
			unset($this->results[0]);
			/* recorremos las lineas de resultado */
			for ($i = 1; $i < 3; $i++)
				/* limpiamos las lineas de resultados */
				$this->results[$i] = $this->clean($this->results[$i]);
			/* ok al mensaje */
			$this->showOK();
		}

		private function clean($data) {
			/* buscamos espacios dobles */
			while (strstr($data, '  '))
				/* eliminamos los espacios dobles */
				$data = str_replace('  ', ' ', $data);
			/* retornamos los resultados limpios */
			return $data;
		}

		private function processData() {
			/* ordenamos los valores */
			$this->ordenarValores();
			/* rearmamos los resultados */
			$this->reordenarResultados();
			/* eliminamos los datos inncesesarios */
			$this->eliminarInnecesarios();
		}

		private function ordenarValores() {
			/* mostramos un mensaje */
			$this->show('Asignando valores..', False);
			/* separamos los valores */
			$this->results[1] = explode(' ', $this->results[1]);
			$this->results[2] = explode(' ', $this->results[2]);
			/* ok al mensaje */
			$this->showOK();
		}

		private function reordenarResultados() {
			/* mostramos un mensaje */
			$this->show('Reordenando resultados..', False);
			/* almacenamos los valores de la RAM */
			$this->almacenar(1, 'ram');
			/* almacenamos los valores de la SWAP */
			$this->almacenar(2, 'swap');
			/* OK al mensaje */
			$this->showOK();
		}

		private function almacenar($type, $title) {
			/* almacenamos el tamano total de la memoria */
			$this->save($type, $title, 'total', 1);
			/* almacenamos el tamano en uso */
			$this->save($type, $title, 'used', 2);
			/* almacenamos el tamano libre */
			$this->save($type, $title, 'free', 3);
			/* almacenamos otros valores */
			$this->saveAnothers($type, $title, Array(
				4 => 'shared',
				5 => 'buffers',
				6 => 'cached'
			));
		}

		private function save($type, $title, $sub, $value) {
			/* almacenamos el resultado */
			$this->results[$title][$sub] = $this->results[$type][$value];
		}

		private function saveAnothers($type, $title, $titles) {
			/* recorremos los demas valores */
			foreach ($titles AS $valor => $titulo) {
				/* verificamos si existen los demas valores a almacenar */
				if (isset($this->results[$type][$valor])) {
					/* almacenamos los valores */
					$this->save($type, $title, $titulo, $valor);
					/* restamos del uso total */
					$this->results[$title]['used'] -= $this->results[$title][$titulo];
				}
			}
		}

		private function eliminarInnecesarios() {
			/* eliminamos los dos indices que no utilizamos */
			unset($this->results[1], $this->results[2]);
		}

		private function catchExceptions($method = Null) {
			/* ingresamos a un control de errores para capturar mis excepciones */
			try {
				/* ingresamos a un control de errores para capturar las excepciones de ejecucion */
				try {
					/* realizamos algunas verificaciones */
					$this->verificarMetodo($method);
					/* obtenemos los parametros recibidos */
					$args = func_get_args();
					/* llamamos al metodo con los parametros */
					call_user_func_array(Array(__CLASS__, $method), $this->buildArgs($args));
				/* capturamos las excepciones */
				} catch (Exception $e) {
					/* capturamos todos los errores y los transformamos en mi excepcion */
					$this->newException($e);
				}
			/* capturamos mis excepciones */
			} catch (MyException $e) {
				/* si se produjo una excepcion la manejamos con el metodo 'show' */
				$this->show($e->getMensaje());
			}
		}
	}
?>